﻿namespace GeostatisticalTool.Classes
{
    using System;
    using System.Collections;
    using DotSpatial.Data;
    using DotSpatial.Topology;
    using DotSpatial.Projections;
    using DotSpatial.Controls;
    using System.Collections.Generic;


    public class IDW : AbstractInterpolator, IInterpolator
    {
        private double weigth;

        public double Weigth
        {
            get { return this.weigth; }
            set { this.weigth = value; }
        }

        /// <summary>
        /// Initializes a new instance of the IDW class
        /// </summary>
        /// <param name="shapeLayer">Shapefile type point</param>
        /// <param name="idField">Position of field that contains the Z value</param>
        public IDW(IFeatureSet shapeLayer, int idField) :
            base(shapeLayer, idField)
        {
            this.method = "IDW";

           // this.CreatePoints(shapeLayer, idField);
          //  this.CalculateDistances();
        }


       new public  ParameterInterpolator GetParameters()
        {
             ParameterInterpolator par = new ParameterInterpolator();
            par.Value= this.weigth;
            return par; 
        }

        new public  void SetParameters(ParameterInterpolator parameters)
        {
            this.weigth = parameters.Value;

        }


        public override double[] Interpolate(double x, double y, double z, bool include)
        {
            List<Kpoint> cpointsF;

            this.Search.ListPointAvailables(out cpointsF, x, y,z, include);

            if (cpointsF.Count == 1)
            {
                return new double[2] { cpointsF[0].W, double.NaN };
            }

            if (cpointsF.Count == 0)
            {
                return new double[2] { double.NaN, double.NaN };
            }

            double sum = 0;
            double totalSum = 0;
            Kpoint pointSearch= new Kpoint(x,y,z,0);
            foreach (Kpoint point in cpointsF)
            { 
                if (pointSearch==point)
                    return new double[2]{point.W, 0};

                double dist=Utils.GetDistance(x,y,z,point);
                double value = Math.Pow(dist, this.weigth);
                sum += (1 / value) * point.W;
                totalSum += (1 / value);
            }

            return new double[2] { sum/totalSum, 0 };

        }

        public override double[] CrossValidation()
        {
            double[] output = new double[2];
            List<Kpoint> cpointsCross = new List<Kpoint>();
            double SSerror = 0;
            int numberUsed = 0;
            double sumError = 0;

            for (int drop = 0; drop < this.NumPoints; drop++)
            {
                cpointsCross = new List<Kpoint>();
                for (int i = 0; i < this.NumPoints; i++)
                    if (i != drop)
                        cpointsCross.Add(this.Kpoints[i]);


                Kpoint value = this.Kpoints[drop];
                double[] inter = this.Interpolate(value.X, value.Y,value.Z,false);
                double error = inter[1];
                if (
                    !inter[0].Equals(double.NaN) )
                {
                    value.Zinte = inter[0];

                        value.SdtError = value.Zinte - value.W;
                        sumError += value.SdtError;
                        SSerror += (value.SdtError * value.SdtError);
                        numberUsed++;
                }
            }

            if (numberUsed > 0)
            {
                output[0] = Math.Sqrt(SSerror / numberUsed); //RMS
                output[1] = sumError / numberUsed; //Mean Prediction errors
            }
            else
            {
                return null;
            }
            return output;
        }
    }
}
